const {fileUtil} = require("./utils/file");
const {config} = require("./config");
const {relProps, getPropsNode} = require("./utils/relProps");
const {parse, compileScript, SFCScriptBlock, compileTemplate} = require("@vue/compiler-sfc");
const path = require("path");
const {relImports} = require("./utils/relImports");
const {relTypeAlias} = require("./utils/relTypeAlias");
const {relPropsAnnotation, relVueAnnotation} = require("./utils/relAnnotation");
const {getExposeNode} = require("./utils/relNode");
const {relExpose} = require("./utils/relExpose");
const {relSlot} = require("./utils/relSlot");
const {relEmits} = require("./utils/relEmits");
const {getGitLog} = require("./utils/relGit");
const {clog} = require("./utils/clog");

// nodejs输出颜色文字，一般来说，字体颜色有这些：31红色，32绿色，33黄色，34蓝色，35紫色，36深绿，37白色；字体背景颜色有这些：40黑色，41红色，42绿色，43黄色，44蓝色，45紫色，46深绿，47白色

function pushFileScanPromise(promiseList, fileList, path) {
    promiseList.push(fileUtil.getVueFiles(path, (filePath, content, fileStats) => {
        fileList.push({
            filePath: filePath,
            content: content,
            fileStats
        })
    }))
}

async function getFileList() {
    const fileList = []
    const promiseList = []
    if (typeof config.scanPath === 'string') {
        pushFileScanPromise(promiseList, fileList, config.scanPath)
    } else if (config.scanPath instanceof Array) {
        for (const path of config.scanPath) {
            pushFileScanPromise(promiseList, fileList, path);
        }
    }
    await Promise.all(promiseList)
    return fileList
}

function relVueFile(file) {
    const {filePath, content, fileStats} = file
    try {
        const vueInfo = {
            name: '',
            // 文件名称
            filename: '',
            // 文件路径
            path: filePath,
            fullPath: path.join(__dirname, '..', filePath),
            // 文件数据
            fileStats,
            // 语言类型
            lang: '',
            // 是否 setup
            setup: false,
            // 属性
            props: null,
            // 事件
            emits: null,
            // 暴露
            exposes: null,
            // 插槽
            slots: null,
            info: {
                desc: ''
            }
        }
        vueInfo.filename = path.basename(filePath)
        vueInfo.name = fileUtil.getVueFileNameKey(filePath)
        const {descriptor, errors} = parse(content)
        if (descriptor.script) {

        } else if (descriptor.scriptSetup) {
            vueInfo.lang = descriptor.scriptSetup.lang
            vueInfo.setup = descriptor.scriptSetup.setup
        }
        // vueInfo.version = descriptor.template.map.version
        const scriptBlock = compileScript(descriptor, {
            id: Date.now() + '' + (Math.floor(Math.random() * 10000))
        })

        if (descriptor.template) {
            const template = compileTemplate({
                source: descriptor.template.content,
                filename: vueInfo.filename,
                id: Date.now() + '' + (Math.floor(Math.random() * 10000))
            })

            vueInfo.slots = relSlot(template)
        }

        vueInfo.info.desc = relVueAnnotation(descriptor)

        // console.log(scriptBlock.scriptAst[2].declaration.properties[2].value.properties[2].body.body[0].expression)

        // const typeAliasMap = relTypeAlias(scriptBlock, descriptor)
        // console.log(typeAliasMap)

        // const importsMap = relImports(scriptBlock, descriptor)
        // console.log(importsMap)

        vueInfo.props = relProps(scriptBlock, descriptor)
        vueInfo.emits = relEmits(scriptBlock)
        vueInfo.exposes = relExpose(scriptBlock)

        return vueInfo
    } catch (e) {
        console.log('\033[31m 文件' + filePath + '编译异常', e)
    }
}

async function relGitLog(fileList) {
    clog('~ 开始异步解析 git 日志').color('cyan').log()
    const gitLogMap = {}
    clog('获取 git 日志ing...').color('cyan').log()
    const gitLogList = await getGitLog()
    clog('解析 git 日志ing...').color('cyan').log()
    // 将文件集合转为路径:index的对象
    const filePathIndexMap = {}
    for (let i = 0; i < fileList.length; i++) {
        const file = fileList[i]
        filePathIndexMap[file.filePath.replace(/\\/g, "/")] = i;
    }
    for (let gitLog of gitLogList) {
        const logFiles = gitLog.files
        if (logFiles && logFiles.length > 0) {
            // 遍历 git 日志的文件
            for (let logFile of logFiles) {
                // 判断日志文件是否在文件集合中
                const fileIndex = filePathIndexMap[logFile]
                if (fileIndex || fileIndex === 0) {
                    const file = fileList[fileIndex]
                    if (file) {
                        const fileName = fileUtil.getVueFileNameKey(file.filePath)
                        // 如果存在，则赋值到日志对象中
                        const gitLogInfo = Object.assign({}, gitLog)
                        delete gitLogInfo.files
                        if (!gitLogMap[fileName]) {
                            gitLogMap[fileName] = []
                        }
                        gitLogMap[fileName].push(gitLogInfo)
                    }
                }
            }
        }
    }
    fileUtil.saveFile('const vueGitLogMap = ' + JSON.stringify(gitLogMap), path.join('analyst/pages', 'vueGitLogOut.js'))
    clog('git 日志解析完成').color('cyan').log()
}

async function relVue() {
    clog('获取文件列表ing...').color('blue').log()
    const fileList = await getFileList()
    const total = fileList.length
    clog(`共获取到${total}个文件`).color('white').log()
    const pageMap = {}
    clog(`正在解析 Vue 文件：${0} / ${total}`).color('blue').inline().log()
    for (let i = 0; i < fileList.length; i++) {
        const file = fileList[i]
        // if (file.filePath !== 'src\\components\\ApiRender.vue') {
        //     continue
        // }
        const vueInfo = relVueFile(file, pageMap)
        pageMap[vueInfo.name] = vueInfo
        clog(`正在解析 Vue 文件：${i + 1} / ${total}`)
            .color('blue')
            .inline()
            .endInline(i + 1 === total)
            .log()
    }
    if (config.showGitLog) {
        relGitLog(fileList)
    }
    return pageMap
}

const startTime = Date.now()
relVue().then(res => {
    fileUtil.saveFile('const vueMap = ' + JSON.stringify(res), path.join('analyst/pages', 'vuePropsOut.js'))
    clog('解析完成！ 耗时：', (Date.now() - startTime) + 'ms').color('green').log()
})
